import logging

from django.apps import apps
from django.core.management.base import BaseCommand

from django_extensions.management.jobs import get_jobs, print_jobs
from django_extensions.management.utils import setup_logger, signalcommand

logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = "Runs scheduled maintenance jobs."

    when_options = [
        "minutely",
        "quarter_hourly",
        "hourly",
        "daily",
        "weekly",
        "monthly",
        "yearly",
    ]

    def add_arguments(self, parser):
        super().add_arguments(parser)
        parser.add_argument(
            "when", nargs="?", help="options: %s" % ", ".join(self.when_options)
        )
        parser.add_argument(
            "--list",
            "-l",
            action="store_true",
            dest="list_jobs",
            default=False,
            help="List all jobs with their description",
        )

    def usage_msg(self):
        print("%s Please specify: %s" % (self.help, ", ".join(self.when_options)))

    def runjobs(self, when, options):
        verbosity = options["verbosity"]
        jobs = get_jobs(when, only_scheduled=True)
        for app_name, job_name in sorted(jobs.keys()):
            job = jobs[(app_name, job_name)]
            if verbosity > 1:
                logger.info("Executing %s job: %s (app: %s)", when, job_name, app_name)
            try:
                job().execute()
            except Exception:
                logger.exception(
                    "ERROR OCCURED IN JOB: %s (APP: %s)", job_name, app_name
                )

    def runjobs_by_signals(self, when, options):
        """Run jobs from the signals"""
        # Thanks for Ian Holsman for the idea and code
        from django_extensions.management import signals
        from django.conf import settings

        verbosity = options["verbosity"]
        for app_name in settings.INSTALLED_APPS:
            try:
                __import__(app_name + ".management", "", "", [""])
            except ImportError:
                pass

        for app in (
            app.models_module for app in apps.get_app_configs() if app.models_module
        ):
            if verbosity > 1:
                app_name = ".".join(app.__name__.rsplit(".")[:-1])
                print("Sending %s job signal for: %s" % (when, app_name))
            if when == "minutely":
                signals.run_minutely_jobs.send(sender=app, app=app)
            elif when == "quarter_hourly":
                signals.run_quarter_hourly_jobs.send(sender=app, app=app)
            elif when == "hourly":
                signals.run_hourly_jobs.send(sender=app, app=app)
            elif when == "daily":
                signals.run_daily_jobs.send(sender=app, app=app)
            elif when == "weekly":
                signals.run_weekly_jobs.send(sender=app, app=app)
            elif when == "monthly":
                signals.run_monthly_jobs.send(sender=app, app=app)
            elif when == "yearly":
                signals.run_yearly_jobs.send(sender=app, app=app)

    @signalcommand
    def handle(self, *args, **options):
        when = options["when"]

        setup_logger(logger, self.stdout)

        if options["list_jobs"]:
            print_jobs(when, only_scheduled=True, show_when=True, show_appname=True)
        elif when in self.when_options:
            self.runjobs(when, options)
            self.runjobs_by_signals(when, options)
        else:
            self.usage_msg()
